from datetime import timedelta, datetime
from typing import Optional

from django.core.exceptions import ObjectDoesNotExist
from django.db import transaction
from django.db.models import F, Case, When, Value, IntegerField, Max
from django.http import HttpResponseRedirect
from alipay import AliPay
from django.utils import timezone
from drf_yasg import openapi
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.permissions import AllowAny

from drf_yasg.utils import swagger_auto_schema
from rest_framework_simplejwt.authentication import JWTAuthentication

from application import settings
from apps.OrderManagement.models import Order, UserPackage
from apps.UserManagement.models import User
from apps.utils.response_utils import api_response, ResponseCode


def handle_new_order(order, new_expire):
    """处理新购订单"""
    # 过期所有历史套餐（保留原始逻辑）
    UserPackage.objects.filter(
        user=order.user,
        expiration_time__gt=timezone.now()
    ).update(status='expired')

    # 创建新套餐
    UserPackage.objects.create(
        user=order.user,
        package=order.package,
        order=order,
        subscription_time=timezone.now(),
        expiration_time=new_expire,
        cost=order.amount
    )


def handle_renewal(order: Order, new_expire: datetime):
    """处理续费（仅影响本套餐）"""
    latest_pkg = UserPackage.objects.filter(
        user=order.user,
        package=order.package
    ).order_by('-expiration_time').first()

    if latest_pkg:
        latest_pkg.expiration_time = new_expire
        latest_pkg.cost += order.amount
        latest_pkg.status = 'active'
        latest_pkg.save()
    else:
        UserPackage.objects.create(
            user=order.user,
            package=order.package,
            order=order,
            subscription_time=timezone.now(),
            expiration_time=new_expire,
            cost=order.amount,
            status='active'
        )


def handle_upgrade(order: Order, new_expire: datetime):
    """处理升级（创建新套餐，不影响其他套餐）"""
    # 过期所有同类型套餐（避免重复）
    UserPackage.objects.filter(
        user=order.user,
        package=order.package,
        expiration_time__gt=timezone.now()
    ).update(status='expired')

    # 创建新套餐记录
    UserPackage.objects.create(
        user=order.user,
        package=order.package,
        order=order,
        subscription_time=timezone.now(),
        expiration_time=new_expire,
        cost=order.amount,
        status='active'
    )


def get_highest_active_package(user: User) -> Optional[UserPackage]:
    """获取当前最高优先级有效套餐"""
    return UserPackage.objects.filter(
        user=user,
        status='active',
        expiration_time__gt=timezone.now()
    ).annotate(
        priority=Case(
            When(package__duration='yearly', then=3),
            When(package__duration='quarter', then=2),
            When(package__duration='monthly', then=1),
            output_field=IntegerField()
        )
    ).order_by('-priority').first()


def calculate_new_expiration(order: Order) -> datetime:
    """计算订单的到期时间（独立套餐版本）"""
    duration_days = order.package.duration_to_days()

    # 查找本套餐最新记录（包括过期但未失效的）
    latest_self_pkg = UserPackage.objects.filter(
        user=order.user,
        package=order.package
    ).order_by('-expiration_time').first()

    # 情况1：存在本套餐未过期记录 -> 续费
    if latest_self_pkg and latest_self_pkg.expiration_time > timezone.now():
        return latest_self_pkg.expiration_time + timedelta(days=duration_days)

    # 情况2：存在本套餐但已过期/无记录 -> 新购
    return timezone.now() + timedelta(days=duration_days)


def get_lower_durations(current_duration):
    """获取比当前低的duration类型"""
    duration_order = ['yearly', 'quarter', 'monthly']
    index = duration_order.index(current_duration)
    return duration_order[index + 1:] if index < len(duration_order) - 1 else []


def get_active_package(user):
    """
    获取当前生效套餐（最高优先级未过期套餐）
    """
    now = timezone.now()
    return UserPackage.objects.filter(
        user=user,
        status='active',
        subscription_time__lte=now,
        expiration_time__gt=now
    ).annotate(
        priority=Case(
            When(package__duration='yearly', then=Value(3)),
            When(package__duration='quarter', then=Value(2)),
            When(package__duration='monthly', then=Value(1)),
            default=Value(0),
            output_field=IntegerField()
        )
    ).order_by('-priority').first()


class AlipayView(APIView):
    """
    处理支付宝支付请求
    """
    permission_classes = [AllowAny]
    authentication_classes = [JWTAuthentication]

    @swagger_auto_schema(
        operation_description="创建订单并生成支付链接",
        request_body=openapi.Schema(
            type=openapi.TYPE_OBJECT,
            properties={
                'order_no': openapi.Schema(type=openapi.TYPE_STRING, description='订单号'),
            }
        ),
        responses={200: '支付链接', 400: '参数错误'},
        tags=["支付管理"]
    )
    def post(self, request, *args, **kwargs):
        order_no = request.data.get('order_no')
        if not order_no:
            return api_response(ResponseCode.BAD_REQUEST, '订单号不能为空')

        try:
            order = Order.objects.get(order_no=order_no)
        except ObjectDoesNotExist:
            return api_response(ResponseCode.BAD_REQUEST, '订单不存在')

        alipay = AliPay(
            appid=settings.ALIPAY_APP_ID,
            app_notify_url=None,
            app_private_key_string=settings.ALIPAY_APP_PRIVATE_KEY,
            alipay_public_key_string=settings.ALIPAY_PUBLIC_KEY,
            sign_type='RSA2',
            debug=True
        )

        order_string = alipay.api_alipay_trade_page_pay(
            out_trade_no=order.order_no,
            total_amount=str(order.amount),
            subject=f"订单 {order.package.name}",
            return_url='http://10.1.13.135:8000/api/payments/alipay/return/'
        )

        # 生成支付链接
        payment_url = f"{settings.ALIPAY_GATEWAY_URL}?{order_string}"
        data = {
            'payment_url': payment_url
        }

        # 将 payment_url 转换为字节类型
        return api_response(ResponseCode.SUCCESS, '支付链接', data)


class AlipayReturnView(APIView):
    """
    处理支付宝支付回调
    """
    permission_classes = [AllowAny]
    authentication_classes = []  # 无需认证

    @swagger_auto_schema(
        operation_description="支付宝支付回调接口",
        responses={200: '支付成功', 400: '支付失败'},
        tags=["支付管理"]
    )
    def get(self, request, *args, **kwargs):
        data = request.GET.dict()
        signature = data.pop('sign', None)

        alipay = AliPay(
            appid=settings.ALIPAY_APP_ID,
            app_notify_url=None,
            app_private_key_string=settings.ALIPAY_APP_PRIVATE_KEY,
            alipay_public_key_string=settings.ALIPAY_PUBLIC_KEY,
            sign_type='RSA2',
            debug=True
        )

        success = alipay.verify(data, signature)
        if success:
            order_no = data.get('out_trade_no')
            trade_no = data.get('trade_no')
            try:
                with transaction.atomic():
                    order = Order.objects.select_for_update().get(order_no=order_no)
                    new_expire = calculate_new_expiration(order)

                    # 根据订单类型处理
                    if order.order_type == 'new':
                        handle_new_order(order, new_expire)
                    elif order.order_type == 'renewal':
                        handle_renewal(order, new_expire)
                    elif order.order_type == 'upgrade':
                        handle_upgrade(order, new_expire)

                    # 更新订单状态
                    order.status = 'completed'
                    order.transaction_id = trade_no
                    order.subscription_time = timezone.now()
                    order.expiration_time = new_expire
                    order.save()

                    return HttpResponseRedirect('http://10.1.13.182:3001/dashboard/subscription')
            except ObjectDoesNotExist:
                return api_response(ResponseCode.BAD_REQUEST, '订单不存在')
            except Exception as e:
                return api_response(ResponseCode.BAD_REQUEST, f'支付失败{str(e)}')
        else:
            return api_response(ResponseCode.BAD_REQUEST, '支付失败')


class AlipayNotifyView(APIView):
    """
    支付宝异步通知接口
    """
    permission_classes = [AllowAny]
    authentication_classes = []  # 无需认证

    @swagger_auto_schema(
        operation_description="支付宝异步通知接口",
        responses={200: '成功', 400: '失败'},
        tags=["支付管理"]
    )
    def post(self, request, *args, **kwargs):
        data = request.POST.dict()
        signature = data.pop('sign', None)

        alipay = AliPay(
            appid=settings.ALIPAY_APP_ID,
            app_notify_url=None,
            app_private_key_string=settings.ALIPAY_APP_PRIVATE_KEY,
            alipay_public_key_string=settings.ALIPAY_PUBLIC_KEY,
            sign_type='RSA2',
            debug=True
        )

        success = alipay.verify(data, signature)
        if success:
            order_no = data.get('out_trade_no')
            trade_no = data.get('trade_no')
            try:
                with transaction.atomic():
                    order = Order.objects.select_for_update().get(order_no=order_no)
                    new_expire = calculate_new_expiration(order)

                    # 根据订单类型处理
                    if order.order_type == 'new':
                        handle_new_order(order, new_expire)
                    elif order.order_type == 'renewal':
                        handle_renewal(order, new_expire)
                    elif order.order_type == 'upgrade':
                        handle_upgrade(order, new_expire)

                    # 更新订单状态
                    order.status = 'completed'
                    order.transaction_id = trade_no
                    order.subscription_time = timezone.now()
                    order.expiration_time = new_expire  # 存储实际计算值
                    order.save()

                    return api_response(ResponseCode.SUCCESS, '支付成功')
            except ObjectDoesNotExist:
                return api_response(ResponseCode.BAD_REQUEST, '订单不存在')
            except Exception as e:
                return api_response(ResponseCode.BAD_REQUEST, f'支付失败{str(e)}')
        else:
            return api_response(ResponseCode.BAD_REQUEST, 'fail')
